/**
 * @file FreeRTOS_app.c
 * @author liufeng (liufeng@injoinic.com)
 * @brief FreeRTOS task.
 * @version 0.1
 * @date 2024-11-07
 *
 * @copyright Copyright (c) 2024  injoinic
 *
 */

#include "FreeRTOS_app.h"
#include "FreeRTOS.h"
#include "bsp_aht21_handler.h"
#include "bsp_iic.h"
#include "queue.h"
#include "shell_port.h"
#include "task.h"

TaskHandle_t StartTask_Handle = NULL; // 用于任务创建
TaskHandle_t PrintTask_Handle = NULL;
TaskHandle_t aht21HandlerTask_Handle = NULL;
TaskHandle_t aht21ReadTask_Handle = NULL;

void StartTask(void* argument);
void PrintTask(void* argument);
void aht21ReadTask(void* argument);

/* ================================ aht21Handler所需要的接口 =========================== */

QueueHandle_t os_queue_create(uint32_t item_num, uint32_t item_size)
{
    return xQueueCreate(item_num, item_size);
}

uint8_t os_queue_get(void* queue_handle, void* item, uint32_t timeout)
{
    return xQueueReceive(queue_handle, item, timeout);
}

uint8_t os_queue_put(void* queue_handle, void* msg, uint32_t timeout)
{
    return xQueueSend(queue_handle, msg, timeout);
}

static aht21_input_func aht21_task_arg = {
    .pf_iic_init = iic_init,
    .pf_iic_deinit = iic_deinit,
    .pf_iic_read_bytes = iic_read_bytes,
    .pf_iic_write_bytes = iic_write_bytes,

    .pf_disable_irq = vPortEnterCritical,
    .pf_enable_irq = vPortExitCritical,

    .pf_delay_ms = vTaskDelay,
    .pf_get_tick = xTaskGetTickCount,

    .pf_queue_create = os_queue_create,
    .pf_queue_get = os_queue_get,
    .pf_queue_put = os_queue_put
};

/* ==================================================================================== */

static const task_attribute task_table[] = {
    // {PrintTask, "PrintTask", 128, NULL, 1, &PrintTask_Handle},
    {aht21HandlerTask, "aht21HandlerTask", 512, &aht21_task_arg, 3, &aht21HandlerTask_Handle},
    // {aht21ReadTask, "aht21ReadTask", 512, NULL, 2, &aht21ReadTask_Handle},
    {shellTask, "shell", 256, &shell, 5, NULL}
};

void FreeRTOS_app()
{
    BaseType_t xReturn = pdPASS;
    xReturn = xTaskCreate(StartTask, "StartTask", 128, NULL, 1, &StartTask_Handle);
    configASSERT(xReturn);

    vTaskStartScheduler();
}

/* -------------------------------------------------------------------------- */
/*                                   start任务                                 */
/* -------------------------------------------------------------------------- */

void StartTask(void* argument)
{
    taskENTER_CRITICAL(); // 进入临界区

    // 根据task_table结构体数组，创建所有任务
    uint16_t task_num = sizeof(task_table) / sizeof(task_attribute);
    for (uint16_t i = 0; i < task_num; i++) {
        BaseType_t xReturn = xTaskCreate(
            task_table[i].pxTaskCode,
            task_table[i].pcName,
            task_table[i].usStackDepth,
            task_table[i].pvParameters,
            task_table[i].uxPriority,
            task_table[i].pxCreatedTask
        );
        configASSERT(xReturn);
    }

    vTaskDelete(StartTask_Handle); // 使命完成，删除

    taskEXIT_CRITICAL();           // 退出临界区
}

/* -------------------------------------------------------------------------- */
/*                                   print任务                                 */
/* -------------------------------------------------------------------------- */

void PrintTask(void* argument)
{
    while (1) {
        printf("Hello,world\r\n");
        vTaskDelay(1000);
    }
}

/* -------------------------------------------------------------------------- */
/*                                aht21_read任务                               */
/* -------------------------------------------------------------------------- */

/**
 * @brief read temprature 、humidity or both, from aht21Handler.
 * @param[in] argument NULL.
 */
void aht21ReadTask(void* argument)
{
    aht21HandlerEventEnum event_msg; // get temp、humi or both
    aht21TempAndHumiType thi_data;   // temprature and humidity data
    if (aht21Handler.is_init == false) {
        // aht21 need about 100ms to power-on init.
        vTaskDelay(100);
    }

    while (1) {
        event_msg = GET_BOTH; // depend on user
        xQueueSend(aht21Handler.event_queue_handle, &event_msg, portMAX_DELAY);

        xQueueReceive(aht21Handler.data_queue_handle, &thi_data, portMAX_DELAY);
        printf("the data timestamp is %d\r\n", aht21Handler.timestamp);

        switch (thi_data.event) {
        case GET_TEMP:
            printf("Temprature is %f\r\n\r\n", thi_data.temprature);
            break;
        case GET_HUMI:
            printf("Humidity is %f%%\r\n\r\n", thi_data.humidity);
            break;
        case GET_BOTH:
            printf("Temprature is %f\r\n", thi_data.temprature);
            printf("Humidity is %f%%\r\n\r\n", thi_data.humidity);
            break;
        default:
            break;
        }
        vTaskDelay(1000);
    }
}

/* -------------------------------------------------------------------------- */
/*                              letter-shell测试函数                           */
/* -------------------------------------------------------------------------- */

void shell_read_aht21()
{
    aht21HandlerEventEnum event_msg; // get temp、humi or both
    aht21TempAndHumiType thi_data;   // temprature and humidity data
    if (aht21Handler.is_init == false) {
        // aht21 need about 100ms to power-on init.
        vTaskDelay(200);
    }

    event_msg = GET_BOTH; // depend on user
    xQueueSend(aht21Handler.event_queue_handle, &event_msg, portMAX_DELAY);

    xQueueReceive(aht21Handler.data_queue_handle, &thi_data, portMAX_DELAY);
    printf("the data timestamp is %d\r\n", aht21Handler.timestamp);
    printf("Temprature is %f\r\n", thi_data.temprature);
    printf("Humidity is %f%%\r\n\r\n", thi_data.humidity);
}

SHELL_EXPORT_CMD(
    SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
    shell_read_aht21,
    shell_read_aht21,
    read aht21 data by letter_shell
);
